mod queue;
mod priority;
mod bounded;
mod unbounded;
mod dispatcher;
mod metrics;
mod stats;

pub use queue::*;
pub use priority::*;
pub use bounded::*;
pub use unbounded::*;
pub use dispatcher::*;
pub use self::metrics::MailboxMetrics;
pub use self::stats::MailboxStats;

use std::sync::Arc;
use tokio::sync::{mpsc, oneshot};
use crate::actor::{Actor, ActorRef};
use crate::context::Context;
use crate::message::{Message, SystemMessage, DynamicMessage};
use crate::errors::SendError;
use std::any::Any;
use std::future::Future;
use std::pin::Pin;

#[async_trait::async_trait]
pub trait MailboxBehavior: Send + Sync {
    async fn post<T: Any + Send + Clone + 'static>(&self, msg: Message<T>) -> Result<(), SendError>;
    async fn post_dynamic(&self, msg: DynamicMessage) -> Result<(), SendError>;
    async fn receive(&self) -> Result<Option<DynamicMessage>, SendError>;
    fn stats(&self) -> MailboxStatus;
}

pub struct MailboxStatus {
    pub messages_received: u64,
    pub messages_processed: u64,
}

#[derive(Debug, Clone)]
pub struct MailboxConfig {
    pub capacity: usize,
    pub throughput: usize,
    pub dispatcher: Arc<dyn MailboxDispatcher>,
    pub metrics_enabled: bool,
}

impl Default for MailboxConfig {
    fn default() -> Self {
        Self {
            capacity: 1000,
            throughput: 100,
            dispatcher: Arc::new(DefaultDispatcher::new(100)),
            metrics_enabled: true,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MailboxState {
    Open,
    Closed,
    Suspended,
}

pub enum Mailbox {
    Unbounded(UnboundedMailbox),
    Bounded(BoundedMailbox),
    Priority(PriorityMailbox),
}

#[async_trait::async_trait]
impl MailboxBehavior for Mailbox {
    async fn post<T: Any + Send + Clone + 'static>(&self, msg: Message<T>) -> Result<(), SendError> {
        match self {
            Self::Unbounded(m) => m.post(msg).await,
            Self::Bounded(m) => m.post(msg).await,
            Self::Priority(m) => m.post(msg).await,
        }
    }

    async fn post_dynamic(&self, msg: DynamicMessage) -> Result<(), SendError> {
        match self {
            Self::Unbounded(m) => m.post_dynamic(msg).await,
            Self::Bounded(m) => m.post_dynamic(msg).await,
            Self::Priority(m) => m.post_dynamic(msg).await,
        }
    }

    async fn receive(&self) -> Result<Option<DynamicMessage>, SendError> {
        match self {
            Self::Unbounded(m) => m.receive().await,
            Self::Bounded(m) => m.receive().await,
            Self::Priority(m) => m.receive().await,
        }
    }

    fn stats(&self) -> MailboxStatus {
        match self {
            Self::Unbounded(m) => m.stats(),
            Self::Bounded(m) => m.stats(),
            Self::Priority(m) => m.stats(),
        }
    }
}

impl Mailbox {
    pub fn new(kind: MailboxKind, config: MailboxConfig) -> Self {
        match kind {
            MailboxKind::Unbounded => Self::Unbounded(UnboundedMailbox::new(config)),
            MailboxKind::Bounded(capacity) => {
                let mut config = config;
                config.capacity = capacity;
                Self::Bounded(BoundedMailbox::new(config))
            }
            MailboxKind::Priority => Self::Priority(PriorityMailbox::new(config)),
        }
    }
}

pub enum MailboxKind {
    Unbounded,
    Bounded(usize),
    Priority,
} 